package cn.exrick.xboot.modules.transport.gps.service;

import cn.exrick.xboot.common.constant.CommonConstant;
import cn.exrick.xboot.common.redis.RedisRepositoryImpl;
import cn.exrick.xboot.modules.transport.gps.config.GPSConfig;
import cn.exrick.xboot.modules.transport.gps.config.GpsErrorCode;
import cn.exrick.xboot.modules.transport.gps.dto.*;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class GpsApiService {

    private final GPSConfig gpsConfig;

    @Autowired
    private RedisRepositoryImpl redisRepository;


    public List<GpsQueryLocationResponse> queryLocation(GpsQueryLocationRequest request) {
        List<GpsQueryLocationResponse> allLocation = new ArrayList<>();
        request.getParams().setLimit_size(100); // 每次查询100条
        Long lastTime = null;
        while (true) {
            // 设置分页参数
            request.getParams().setLast_time(lastTime);
            // 调用API
            TypeReference<GpsResponse<List<GpsQueryLocationResponse>>> typeRef = new TypeReference<GpsResponse<List<GpsQueryLocationResponse>>>() {
            };
            GpsResponse<List<GpsQueryLocationResponse>> response = this.callWithToken(request, typeRef);
            if (response == null || (CollectionUtil.isEmpty(response.getItems())  && (CollectionUtil.isEmpty(response.getData())))) {
                break;
            }
            // 添加本页数据
            allLocation.addAll(response.getData());

            // 获取最后一条数据的信息
            GpsQueryLocationResponse lastLocation = response.getData().get(response.getData().size() - 1);
            lastTime = lastLocation.getTime();
            // 如果获取的数据少于限制数，说明已经是最后一页
            if (response.getIs_finish()) {
                break;
            }

            // 避免频繁请求
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
        return allLocation;
    }

    public List<GpsFindDevResponse> findDevices(GpsFindDevRequest request) {
        TypeReference<GpsResponse<GpsFindDevResponse>> typeRef = new TypeReference<GpsResponse<GpsFindDevResponse>>() {};
        GpsResponse<GpsFindDevResponse> gpsFindDevResponseGpsResponse = this.callWithToken(request, typeRef);
        return gpsFindDevResponseGpsResponse.getItems();
    }

    public String getGpsLogin(GpsLoginRequest request) {
        request.getParams().setAccount(gpsConfig.getAccount());
        request.getParams().setPwd_md5(gpsConfig.getApiPwdMd5());
        request.getParams().setType(gpsConfig.getType());
        GpsLoginResponse call = this.call(request);
        if (call == null || call.getSid() == null) {
            log.warn("获取GPS登录令牌失败");
            return null;
        }
        String sid = call.getSid();
        redisRepository.setExpire(CommonConstant.GPS_TOKEN_REDIS_KEY,sid, gpsConfig.getTokenExpire());
        return sid;
    }
    private String getOrRefreshToken() {
        String token = redisRepository.get(CommonConstant.GPS_TOKEN_REDIS_KEY);
        if (token == null) {
            log.info("GPS token不存在，重新获取");
            GpsLoginRequest request = new GpsLoginRequest();
            request.getParams().setAccount(gpsConfig.getAccount());
            request.getParams().setPwd_md5(gpsConfig.getApiPwdMd5());
            request.getParams().setType(gpsConfig.getType());
            token = getGpsLogin(request);
        }
        return token;
    }
    //
    /**
     * 通用JSON请求方法
     * @return 接口响应体
     */
    public <T> GpsLoginResponse call(T param) {
        try {
            // 发送JSON请求
            HttpResponse response = HttpRequest.post(gpsConfig.getBaseurl())
                    .contentType(ContentType.JSON.getValue())
                    .body(JSONUtil.toJsonStr(param))
                    .timeout(gpsConfig.getTimeout())
                    .execute();
            // 解析响应
            String body = response.body();
            GpsLoginResponse result = JSONUtil.toBean(body, GpsLoginResponse.class);

            // 处理业务错误
            if (result.getErrcode() != 0) {
                log.warn("GPS API调用不成功: 错误码：｛｝， 错误消息:{}" ,result.getErrcode(), result.getError_message());
                return null;
            }
            return result;
        } catch (Exception e) {
            log.error("GPS API调用异常: ", e);
            return null;
        }
    }

    /**
     * 带Token的通用JSON请求方法
     */
    public <T, R> GpsResponse<R> callWithToken(T param, TypeReference<GpsResponse<R>> resultType) {
        String token = getOrRefreshToken();
        if (token == null) {
            log.error("无法获取GPS token");
            return null;
        }

        try {
            // 添加sid参数到URL
            String url = gpsConfig.getBaseurl() + "?sid=" + token;

            // 发送JSON请求
            HttpResponse response = HttpRequest.post(url)
                    .contentType(ContentType.JSON.getValue())
                    .body(JSONUtil.toJsonStr(param))
                    .timeout(gpsConfig.getTimeout())
                    .execute();

            // 解析响应
            String body = response.body();
            GpsResponse<R> result = JSONUtil.toBean(body, resultType, true);

            // 处理token过期情况
            if (result.getErrcode().equals(GpsErrorCode.TOKEN_EXPIRED_CODE.getCode())) {
                log.info("GPS token已过期，重新获取");
                // 清除旧token
                redisRepository.del(CommonConstant.GPS_TOKEN_REDIS_KEY);
                // 重新获取token
                GpsLoginRequest gpsLoginRequest = new GpsLoginRequest();
                token = getGpsLogin(gpsLoginRequest);
                if (token == null) {
                    return null;
                }
                // 使用新token重试请求
                url = gpsConfig.getBaseurl() + "?sid=" + token;
                response = HttpRequest.post(url)
                        .contentType(ContentType.JSON.getValue())
                        .body(JSONUtil.toJsonStr(param))
                        .timeout(gpsConfig.getTimeout())
                        .execute();
                result = JSONUtil.toBean(response.body(), resultType, true);
            }

            // 处理业务错误
            if (result.getErrcode() != 0) {
                log.warn("GPS API调用不成功: 错误码：{}，错误消息:{}", result.getErrcode(), result.getError_message());
                return null;
            }
            return result;
        } catch (Exception e) {
            log.error("GPS API调用异常: ", e);
            return null;
        }
    }

}
